﻿#include "function_frank_match.h"

// Local procedures 
void createFrankMatch(HObject ho_image, HObject *ho_xld_show, HTuple hv_row1, HTuple hv_column1,
	HTuple hv_row2, HTuple hv_column2, HTuple *hv_ret, HTuple *hv_model)
{

	// Local iconic variables
	HObject  ho_ImageResult, ho_ROI, ho_ImageReduced;
	HObject  ho_Region, ho_ConnectedRegions, ho_SelectedRegion;
	HObject  ho_RectangleMask, ho_RegionBorder, ho_RegionDifference;
	HObject  ho_RegionBorderDilation, ho_ImageReducedBorder;
	HObject  ho_ModelContours;

	// Local control variables
	HTuple  hv_UsedThreshold, hv_Row11, hv_Column11;
	HTuple  hv_Row21, hv_Column21, hv_NumberNow, hv_Message;
	HTuple  hv_model_row, hv_model_column, hv_model_angle, hv_Score;
	HTuple  hv_HomMat2D;

	MultImage(ho_image, ho_image, &ho_ImageResult, 0.003, 0);
	GenRectangle1(&ho_ROI, hv_row1, hv_column1, hv_row2, hv_column2);
	ReduceDomain(ho_ImageResult, ho_ROI, &ho_ImageReduced);
	BinaryThreshold(ho_ImageReduced, &ho_Region, "max_separability", "dark", &hv_UsedThreshold);
	FillUp(ho_Region, &ho_Region);
	Connection(ho_Region, &ho_ConnectedRegions);
	SelectShapeStd(ho_ConnectedRegions, &ho_SelectedRegion, "max_area", 70);

	SmallestRectangle1(ho_SelectedRegion, &hv_Row11, &hv_Column11, &hv_Row21, &hv_Column21);
	GenRectangle1(&ho_RectangleMask, hv_Row11 + ((hv_Row21 - hv_Row11) / 4), hv_Column11 - 10,
		hv_Row21 - ((hv_Row21 - hv_Row11) / 4), hv_Column11 + 500);


	CountObj(ho_SelectedRegion, &hv_NumberNow);
	if (0 != (int(hv_NumberNow < 1)))
	{
		(*hv_ret) = -1;
		hv_Message = "blob not find";
		return;
	}

	Boundary(ho_SelectedRegion, &ho_RegionBorder, "outer");
	Difference(ho_RegionBorder, ho_RectangleMask, &ho_RegionDifference);



	DilationCircle(ho_RegionDifference, &ho_RegionBorderDilation, 5);

	Intersection(ho_RegionBorderDilation, ho_ROI, &ho_RegionBorderDilation);

	ReduceDomain(ho_image, ho_RegionBorderDilation, &ho_ImageReducedBorder);
	CreateShapeModel(ho_ImageReducedBorder, "auto", -0.39, 0.79, "auto", "auto", "use_polarity",
		"auto", "auto", &(*hv_model));
	GetShapeModelContours(&ho_ModelContours, (*hv_model), 1);
	FindShapeModel(ho_image, (*hv_model), -0.39, 0.79, 0.5, 1, 0.5, "least_squares",
		0, 0.9, &hv_model_row, &hv_model_column, &hv_model_angle, &hv_Score);
	if (0 != (int((hv_Score.TupleLength()) < 0)))
	{
		(*hv_ret) = -1;
		hv_Message = "model_match not match";
		return;
	}
	VectorAngleToRigid(0, 0, 0, hv_model_row, hv_model_column, hv_model_angle, &hv_HomMat2D);
	AffineTransContourXld(ho_ModelContours, &(*ho_xld_show), hv_HomMat2D);
	//dilation_circle (SelectedRegion, SelectedRegion, distance)
	//difference (Rectangle, SelectedRegion, xld_show)
	(*hv_ret) = 1;

}


void frankMatch(HObject ho_image, HObject *ho_xld_show, HTuple hv_model, HTuple *hv_score,
	HTuple *hv_ret)
{

	// Local iconic variables
	HObject  ho_ObjectSelected;

	// Local control variables
	HTuple  hv_ModelRow, hv_ModelColumn, hv_ModelAngle;
	HTuple  hv_HomMat2D;

	FindShapeModel(ho_image, hv_model, -0.39, 0.79, 0.1, 1, 0.5, "none", 0, 0.9, &hv_ModelRow,
		&hv_ModelColumn, &hv_ModelAngle, &(*hv_score));

	if (0 != (int(((*hv_score).TupleLength()) == 0)))
	{
		(*hv_ret) = -1;
		return;
	}
	GetShapeModelContours(&(*ho_xld_show), hv_model, 1);
	VectorAngleToRigid(0, 0, 0, hv_ModelRow, hv_ModelColumn, hv_ModelAngle, &hv_HomMat2D);
	AffineTransContourXld((*ho_xld_show), &(*ho_xld_show), hv_HomMat2D);


	SelectObj((*ho_xld_show), &ho_ObjectSelected, 1);

	(*hv_ret) = 1;

}

DetectionFrankMatch::DetectionFrankMatch(QDialog* parent, QSettings* qsettings, QString section, QString dir) : QDialog(parent)
{
	m_dir = dir + "/" + section;
	m_qsettings = qsettings;

	m_section = section;

	/*m_create_shape_model = new FunctionCreateShapeModel(this, dir, section);*/

	this->setWindowTitle(("find shape model"));
	QRect desktop_rect = QApplication::desktop()->geometry();
	double ratio_x = desktop_rect.width() / 1920.0;
	double ratio_y = desktop_rect.height() / 1080.0;

	move(0, 0);
	this->setFixedSize(1920 * ratio_x, 1010 * ratio_y);

	QHBoxLayout* hlayout = new QHBoxLayout();
	this->setLayout(hlayout);



	QFrame* p = new QFrame(this);
	QSize control_size(240 * ratio_x, 40 * ratio_y);
	p->setFrameShape(QFrame::WinPanel);
	p->move(0 * ratio_x, 0 * ratio_y);
	p->setFixedSize(600 * ratio_x, 800 * ratio_y);

	hlayout->addWidget(p);

	QGridLayout *qgridLayout = new QGridLayout();
	p->setLayout(qgridLayout);

	int index = 0;

	QSize ButtonSize(220 * ratio_x, 40 * ratio_y);


	m_qlabel_score_standard = new QLabel();
	m_qlabel_score_standard->setText("Match Score");
	m_qlabel_score_standard->setFixedSize(control_size);
	qgridLayout->addWidget(m_qlabel_score_standard, index, 0);
	m_qdoublespinbox_score_standard = new QDoubleSpinBox();
	m_qdoublespinbox_score_standard->setFixedSize(control_size);
	m_qdoublespinbox_score_standard->setMinimum(0);
	m_qdoublespinbox_score_standard->setMaximum(1);
	qgridLayout->addWidget(m_qdoublespinbox_score_standard, index, 1);
	index++;

	QPushButton* p_QPushButton = new QPushButton(this);
	p_QPushButton->setFixedSize(control_size);
	p_QPushButton->setText("Draw ROI");
	connect(p_QPushButton, &QPushButton::clicked, this, [=]() {
		m_view->m_pixmapItem->m_shape_type = 1;
		m_view->m_pixmapItem->m_color = Qt::blue;
		m_view->m_pixmapItem->m_bool_filled = false;
	});
	qgridLayout->addWidget(p_QPushButton, index, 0);


	m_pushbutton_create_new_model = new QPushButton(this);
	m_pushbutton_create_new_model->setFixedSize(control_size);
	m_pushbutton_create_new_model->setText("Create Model");
	connect(m_pushbutton_create_new_model, &QPushButton::clicked, this, &DetectionFrankMatch::createModel);
	qgridLayout->addWidget(m_pushbutton_create_new_model, index, 0);

	m_pushbutton_show_model = new QPushButton(this);
	m_pushbutton_show_model->setFixedSize(control_size);
    m_pushbutton_show_model->setText("Show Model");
	connect(m_pushbutton_show_model, &QPushButton::clicked, this, &DetectionFrankMatch::showModel);
	qgridLayout->addWidget(m_pushbutton_show_model, index, 1);
    m_pushbutton_show_model->setVisible(false);
	index++;

	m_pushbutton_show_orign_image = new QPushButton(this);
	m_pushbutton_show_orign_image->setFixedSize(control_size);
    m_pushbutton_show_orign_image->setText("ShowOrign");
	connect(m_pushbutton_show_orign_image, &QPushButton::clicked, this, [=]() {
		QImage q_image = matToQImage(m_image);
		m_view->setImage(q_image, "");
		return true;
	});
	qgridLayout->addWidget(m_pushbutton_show_orign_image, index, 0);
	m_pushbutton_detection = new QPushButton(this);
	m_pushbutton_detection->setFixedSize(control_size);
	m_pushbutton_detection->setText("Detection");
	connect(m_pushbutton_detection, &QPushButton::clicked, this, &DetectionFrankMatch::detectionImage);
	qgridLayout->addWidget(m_pushbutton_detection, index, 1);
	index++;

	m_pushbutton_save_parameter = new QPushButton(this);
	m_pushbutton_save_parameter->setFixedSize(control_size);
	m_pushbutton_save_parameter->setText("Save");
	connect(m_pushbutton_save_parameter, &QPushButton::clicked, this, &DetectionFrankMatch::saveParameter);
	qgridLayout->addWidget(m_pushbutton_save_parameter, index, 0);

	m_pushbutton_return = new QPushButton(this);
	m_pushbutton_return->setFixedSize(control_size);
	m_pushbutton_return->setText("Exit");
	qgridLayout->addWidget(m_pushbutton_return, index, 1);
	connect(m_pushbutton_return, &QPushButton::clicked, this, [=]() {
		this->hide();
	});



	{//加入图像显示
		QVBoxLayout* view_layout = new QVBoxLayout();
		view_layout->setMargin(0);
		m_view = new QtQGraphicsView(this);
		m_view->setFixedSize(1250 * ratio_x, 900 * ratio_y);
		
		row1 = 100;
		column1 = 100;
		row2 = 400;
		column2 = 400;

		m_graphics_shape_rectangle = new GraphicsShapeRectangleCirce(column1, row1, column2 - column1, row2 - row1, Qt::blue);
		m_graphics_shape_rectangle->setShapeType(0);
		m_graphics_shape_rectangle->setFilled(false);
		m_view->m_scene->addItem(m_graphics_shape_rectangle);

		connect(m_view->m_pixmapItem, &QtQGraphicsPixmapItem::sendMessage, this, [=](QPointF pos, QString message)
		{
			Q_UNUSED(pos);
			m_view_pixel_qlabel->setText(message);
		});
		view_layout->addWidget(m_view);
		m_view_pixel_qlabel = new QLabel(this);
		m_view_pixel_qlabel->setAlignment(Qt::AlignRight);
		m_view_pixel_qlabel->setText("");
		m_view_pixel_qlabel->setFixedSize(1250 * ratio_x, 20 * ratio_y);
		view_layout->addWidget(m_view_pixel_qlabel);
		hlayout->addLayout(view_layout);
	}
	loadParameter();
}

DetectionFrankMatch::~DetectionFrankMatch()
{
	;
}

bool DetectionFrankMatch::detection(HObject image_in, QString& message)
{
	try
	{
		if (m_model.Length() == 0)
		{
			message = "no model";
			return false;
		}

		HTuple hv_ret, hv_max_value;
		frankMatch(image_in, &m_xld_show, m_model, &hv_max_value, &hv_ret);


		int ret = hv_ret[0].I();

		if (ret > 0)
		{
			double score = hv_max_value[0].D();


			if (score > m_score_standard)
				return true;
			else
			{
				message = "frank match NG" +  QString::number(score);
				return false;
			}
		}
		else
		{
			message = "frank match NG no find";
			return false;
		}
	}
	catch (HException &HDevExpDefaultException)
	{
		message = HDevExpDefaultException.ErrorMessage();
		return false;
	}

	return true;
}

void DetectionFrankMatch::detectionImage()
{
	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}

	QString message;
	HObject image = matToHImage(m_image);
	bool state = detection(image, message);


	if (state)
		message += "OK";
	else
		message += "NG";
	Mat image_show = m_image.clone();
	draw(image_show, image_show);

	QImage q_image = matToQImage(image_show);

	m_view->setImage(q_image, message);

}

void DetectionFrankMatch::draw(Mat image_in, Mat& image_out)
{
	if (image_in.empty())
	{
		return;
	}
	if (image_in.channels() == 1)
	{
		cvtColor(image_in, image_in, COLOR_GRAY2BGR);
	}


	image_out = drawXld(image_in, m_xld_show, Scalar(0, 255, 0));
	m_xld_show.Clear();
}

void DetectionFrankMatch::loadParameter()
{
	row1 = m_qsettings->value(m_section + "/" + "ROI0row1", 100).toInt();
	column1 = m_qsettings->value(m_section + "/" + "ROI0column1", 100).toInt();
	row2 = m_qsettings->value(m_section + "/" + "ROI0row2", 200).toInt();
	column2 = m_qsettings->value(m_section + "/" + "ROI0column2", 200).toInt();

	m_graphics_shape_rectangle->m_points[0].setY(row1);
	m_graphics_shape_rectangle->m_points[0].setX(column1);
	m_graphics_shape_rectangle->m_points[1].setY(row2);
	m_graphics_shape_rectangle->m_points[1].setX(column2);

	m_score_standard = m_qsettings->value(m_section + "/" + "m_score_standard").toDouble();

	m_qdoublespinbox_score_standard->setValue(m_score_standard);

	try {
		ReadShapeModel((m_dir + "/model.shm").toLocal8Bit().toStdString().c_str(), &m_model);
	}
	catch (HException &HDevExpDefaultException) {
		QString message = HDevExpDefaultException.ErrorMessage().Text();
		return;
	}
	m_image_model = imread((m_dir + "/image.png").toLocal8Bit().toStdString(), -1);
	return;
}

void DetectionFrankMatch::saveParameter()
{
	
	int i = 0;
	QRectF qrectf = m_graphics_shape_rectangle->boundingRect();
	row1 = m_graphics_shape_rectangle->pos().y() + (int)qrectf.y();
	column1 = m_graphics_shape_rectangle->pos().x() + (int)qrectf.x();
	row2 = m_graphics_shape_rectangle->pos().y() + (int)(qrectf.y() + qrectf.height());
	column2 = m_graphics_shape_rectangle->pos().x() + (int)(qrectf.x() + qrectf.width());
	m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "row1", row1);
	m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "column1", column1);
	m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "row2", row2);
	m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "column2", column2);
	

	m_score_standard = m_qdoublespinbox_score_standard->value();
	m_qsettings->setValue(m_section + "/" + "m_score_standard", m_score_standard);

	if (!QDir().exists(m_dir))
	{
		QDir().mkpath(m_dir);
	}


	

	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}
	imwrite((m_dir + "/image.png").toLocal8Bit().toStdString(), m_image_model);

	try {
		if (m_model.Length() == 0)
		{
			QMessageBox::information(nullptr, "", "no model");
			return;
		}
		WriteShapeModel(m_model, (m_dir + "/model.shm").toLocal8Bit().toStdString().c_str());
	}
	catch (HException &HDevExpDefaultException) {
		QString message = HDevExpDefaultException.ErrorMessage().Text();
		QMessageBox::information(nullptr, "", message);
		return;
	}
	return;
}

bool DetectionFrankMatch::showDialog()
{
	QImage q_image = matToQImage(m_image);
	m_view->setImage(q_image, "");

	return true;
}


void DetectionFrankMatch::createModel()
{
	QString message;
	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}
	try
	{
		HTuple hv_ret;
		QString message;
		HObject image = matToHImage(m_image);

		

		createFrankMatch(image, &m_xld_model, row1,column1,row2,column2, &hv_ret, &m_model);
		
		int ret = hv_ret[0].I();

		if (ret > 0)
		{
			message = "Create Model OK";
		}
		else
		{
			message = "Create Model NG";
		}
	}
	catch (HException &HDevExpDefaultException)
	{
		message = HDevExpDefaultException.ErrorMessage();
	}
	m_image_model = m_image.clone();
	Mat image_show = m_image_model.clone();
	if (image_show.empty())
	{
		return;
	}
	if (image_show.channels() == 1)
	{
		cvtColor(image_show, image_show, COLOR_GRAY2BGR);
	}
	image_show = drawXld(image_show, m_xld_model, Scalar(0, 255, 0));
	QImage q_image = matToQImage(image_show);


	m_view->setImage(q_image, message);
}

void DetectionFrankMatch::showModel()
{
	Mat image_show = m_image_model.clone();
	if (image_show.empty())
	{
		return;
	}
	if (image_show.channels() == 1)
	{
		cvtColor(image_show, image_show, COLOR_GRAY2BGR);
	}
	image_show = drawXld(image_show, m_xld_model, Scalar(0, 255, 0));
	QImage q_image = matToQImage(image_show);

	m_view->setImage(q_image, "");;
}
